//使用cpp-httplib搭建网络通信服务器
#ifndef _M_SERVICE
#define _M_SERVICE
#include "data.hpp"
#include "httplib.h"
extern tqbcloud::DataManager _Data;
namespace tqbcloud
{
    class Service
    {
    private:
        int _server_port;
        std::string _server_ip;
        std::string _url_prefix;
        httplib::Server _srv;

    public:
        static void Upload(const httplib::Request &req, httplib::Response &rsp)//浏览器或客户端上传
        {

            if (req.has_file("file") == false)
            {
                rsp.status = 400;
                return;
            }
            const auto &file = req.get_file_value("file");
            tqbcloud::Config *con = tqbcloud::Config::getinstance();
            std::string _real_path = con->GetBackDir();
            std::string _url_path = con->GetURLPrefix();
            std::string name_ = tqbcloud::Fileutil(file.filename).FileName();
            std::cout<<name_<<std::endl;
            std::string realpath = _real_path + name_;
            std::string urlpath = _url_path + name_;
            tqbcloud::Fileutil fu(realpath);
            std::string body;
            fu.SetContent(&(file.content));
            tqbcloud::BackupInfo b;
            b.NewBackupInfo(realpath);
            _Data.Insert(urlpath, b);
            rsp.status = 200;
        }
        static void List(const httplib::Request &req, httplib::Response &rsp)//浏览器展示
        {
            std::vector<BackupInfo> arry;
            _Data.GetAll(&arry);
            std::stringstream ss;
            ss << "<html><head><title>Download</title></head>";
            ss << "<body><h1>Download</h1><table>";
            std::string qm = "\"";
            for (auto &i : arry)
            {
                ss << "<tr>";
                ss << "<td>";
                ss << "<a href=" + qm + i._url + qm + ">" + tqbcloud::Fileutil(i._realpath).FileName() + "</a></td>";
                ss << "<td align=" + qm + "right" + qm + ">" + ctime(&i._mtime) + "</td>";
                ss << "<td align=" + qm + "right" + qm + ">" << i._fsize / 1024 << "k</td>";
                ss << "</tr>";
            }
            ss << "</table></body></html>";
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
            return;
        }
        static std::string GETetag(tqbcloud::BackupInfo b)//唯一标识文件，用于判断文件是否被修改
        {
            std::string etag;
            tqbcloud::Fileutil tmp(b._realpath);
            etag = tmp.FileName();
            etag += "-";
            etag += std::to_string(tmp.FileSize());
            etag += "-";
            etag += std::to_string(b._mtime);
            return etag;
        }
        static void Download(const httplib::Request &req, httplib::Response &rsp)//浏览器下载
        {
            tqbcloud::BackupInfo b;
            _Data.GetOneByURL(req.path, &b);
            if (b._pack_flag == true)
            {
                tqbcloud::Fileutil fu(b._packpath);
                fu.UnCompress(b._realpath);
                fu.Remove(b._packpath);
                b._pack_flag = false;
                _Data.Update(b._url, b);
            }
            tqbcloud::Fileutil f(b._realpath);
            f.GetContent(&rsp.body);
            rsp.set_header("Accept-Ranges", "byte");
            rsp.set_header("ETag", GETetag(b));
            rsp.set_header("Content-Type", "application/octet-stream;charset=utf-8");
            // rsp.status=200;

            //断点重传：需要告诉服务器下载区间范围；服务器上要能够检测上一次下载之后这个文件是否被修改过
            //httplib源码已经实现了这个功能 只需要将数据读取到rsp.body中即可 做个笔记方便自己复习
            
            //原理：
            //第一次文件下载
            //GET /download/test.txt HTTP/1.1
            //...

            //HTTP/1.1 200 OK
            //Accept-Ranges:byte 告诉客户端服务器支持断点续传功能
            //ETag：“文件唯一标识” 客户端收到响应会保存这个信息.
            //...
            //文件数据为正文
            

            //断点续传
            //GET /download/test.txt HTTP/1.1
            //if-Range:"第一次下载时服务端响应的etag字段，用于判断这个文件与原先下载的文件是否一致"
            //Range:bytes=100-10000 告诉服务器客户端需要的数据区间范围
            
            //HTTP/1.1 206 Partial Content
            //ETag：“文件唯一标识” 客户端收到响应会保存这个信息.
            //Content-Range:bytes 100-10000/文件大小
            //正文为对应的区间数据

            
        }

    public:
        Service()
        {
            tqbcloud::Config *con = tqbcloud::Config::getinstance();
            _server_port = con->GetServerPort();
            _server_ip = con->GetServerIp();
            _url_prefix = con->GetURLPrefix();
        }
        bool RunModule()
        {
            _srv.Post("/upload", Upload);
            _srv.Get("/", List);
            _srv.Get("/listshow", List);
            _srv.Get("/download/(.*)", Download);
            bool ret = _srv.listen("0.0.0.0", _server_port);
            return true;
        }
    };

}
#endif
